#include <linux/fs.h>
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/module.h> /* Needed by all modules */
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <netctl_fs.h>
#include <netctl_list.h>

const static char cmd[] = "nc";
static char       fullpath[512];

// LIST_HEAD(exec_path_list);
struct list_head exec_path_list = LIST_HEAD_INIT(exec_path_list);

static int find_entry(const char* fullpath)
{
    struct exec_path_entry *ptr, *next;
    list_for_each_entry_safe(ptr, next, &exec_path_list, list)
    {
        if (!strncmp(ptr->fullpath, fullpath, strlen(ptr->fullpath))) return 1;
    }
    // not founded.
    return 0;
}

static unsigned int linx_nf_hookfn(unsigned int hooknum, struct sk_buff* skb,
                                   const struct net_device* in,
                                   const struct net_device* out,
                                   int (*okfn)(struct sk_buff*))
{
    char* path;
    if (!(current->mm)) return NF_ACCEPT;
    if (!(current->mm->exe_file)) return NF_ACCEPT;

    path = d_path(&(current->mm->exe_file->f_path), fullpath, 512);
    if (find_entry(path)) {
        // if(1){
        printk("current cmd:%s path:%s len:%ld\n", current->comm, path,
               strlen(path));
        return NF_DROP;
    }
    return NF_ACCEPT;
}

static struct nf_hook_ops ops = {
    .hook     = linx_nf_hookfn,
    .owner    = THIS_MODULE,
    .pf       = NFPROTO_IPV4,
    .hooknum  = NF_INET_LOCAL_IN,
    .priority = NF_IP_PRI_FILTER,
};

int init_module(void)
{
    int ret;
    ret = ltcs_sysfs_init();
    if (ret) return ret;
    ret = nf_register_hook(&ops);
    if (ret) return ret;
    printk(KERN_INFO "netctl init.\n");
    return 0;
}

void cleanup_module(void)
{
    nf_unregister_hook(&ops);
    ltcs_sysfs_free();
    ltcs_list_del_all();
    printk(KERN_INFO "netctl exit.\n");
}
MODULE_LICENSE("GPL");
